package org.geektimes.injection.initializer;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.geektimes.common.function.Attempt;
import org.geektimes.injection.comparator.Order;
import org.geektimes.injection.component.Component;
import org.geektimes.injection.context.ComponentContext;
import org.geektimes.injection.context.Initializer.IncludeComponentInitializer;

import javax.annotation.PreDestroy;
import javax.servlet.ServletContext;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

@Order(1)
public class ComponentInitializerInitializer implements WebApplicationContextInitializer {

    @Override
    public void contextInitialized(ServletContext servletContext) {
        ComponentContext componentContext = new ComponentContext(servletContext);
        try {
            componentContext.init();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void contextDestroyed(ServletContext servletContext) {
        ComponentContext componentContext = 
                (ComponentContext) servletContext.getAttribute(ComponentContext.CONTEXT_NAME);

        // 销毁第三方组件
        Properties properties = componentContext.getProperties();
        String outComponentClassNames = properties.getProperty(ComponentContext.OUT_COMPONENT_CLASS_NAMES);
        if (StrUtil.isNotBlank(outComponentClassNames)) {
            Arrays.stream(outComponentClassNames.split(","))
                    .map(String::trim)
                    .filter(StrUtil::isNotBlank)
                    .map(Attempt.apply(ComponentContext.class.getClassLoader()::loadClass))
                    .filter(IncludeComponentInitializer.class::isAssignableFrom)
                    .map(Attempt.apply(Class::newInstance))
                    .map(IncludeComponentInitializer.class::cast)
                    .forEach(Attempt.accept(c -> c.destroy(componentContext)));
        }
        
        // 销毁内置组件
        Map<String, Component> container = componentContext.getContainer();
        for (Map.Entry<String, Component> entry : container.entrySet()) {
            Component component = entry.getValue();
            Object bean = component.getBean();
            Class<?> beanClass = bean.getClass();
            for (Method method : beanClass.getMethods()) {
                PreDestroy preDestroy = method.getAnnotation(PreDestroy.class);
                if (ObjectUtil.isNotEmpty(preDestroy)) {
                    try {
                        method.invoke(bean);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
